package com.hsl.housaileibot001.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hsl.housaileibot001.mapper.RefreshTokenMapper;
import com.hsl.housaileibot001.mapper.UserMapper;
import com.hsl.housaileibot001.model.RefreshToken;
import com.hsl.housaileibot001.model.User;
import com.hsl.housaileibot001.model.dto.RefreshTokenDTO;
import com.hsl.housaileibot001.model.dto.UserLoginDTO;
import com.hsl.housaileibot001.model.dto.UserRegisterDTO;
import com.hsl.housaileibot001.model.vo.LoginVO;
import com.hsl.housaileibot001.model.vo.UserInfoVO;
import com.hsl.housaileibot001.service.UserService;
import com.hsl.housaileibot001.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 用户服务实现类
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RefreshTokenMapper refreshTokenMapper;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    @Transactional
    public LoginVO login(UserLoginDTO loginDTO) {
        // 查找用户
        User user = findByUsername(loginDTO.getUsername());
        if (user == null) {
            throw new RuntimeException("用户名或密码错误");
        }

        // 验证密码
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new RuntimeException("用户名或密码错误");
        }

        // 检查用户状态
        if (!"ACTIVE".equals(user.getStatus())) {
            throw new RuntimeException("用户已被禁用");
        }

        // 更新最后登录时间
        // 使用乐观锁更新时，MyBatis Plus会自动处理version字段
        // 但需要确保version字段有值，如果为null则设置默认值1
        if (user.getVersion() == null) {
            user.setVersion(1);
        }
        user.setLastLoginTime(LocalDateTime.now());
        user.setUpdatedTime(LocalDateTime.now());
        
        // 使用updateById更新，MyBatis Plus会自动处理version字段的递增
        boolean updated = userMapper.updateById(user) > 0;
        if (!updated) {
            // 如果更新失败，可能是乐观锁冲突，记录日志但不影响登录流程
            log.warn("更新用户最后登录时间失败，可能是乐观锁冲突: userId={}", user.getId());
        }

        // 生成token
        String accessToken = jwtUtil.generateAccessToken(user.getId(), user.getUsername(), user.getRole());
        String refreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername());

        // 保存refresh token到数据库
        RefreshToken refreshTokenEntity = new RefreshToken();
        refreshTokenEntity.setUserId(user.getId());
        refreshTokenEntity.setToken(refreshToken);
        refreshTokenEntity.setExpiresAt(LocalDateTime.now().plusDays(7));
        refreshTokenEntity.setCreatedTime(LocalDateTime.now());
        refreshTokenMapper.insert(refreshTokenEntity);

        // 构建返回结果
        LoginVO loginVO = new LoginVO();
        loginVO.setAccessToken(accessToken);
        loginVO.setRefreshToken(refreshToken);

        UserInfoVO userInfo = new UserInfoVO();
        userInfo.setId(user.getId());
        userInfo.setUsername(user.getUsername());
        userInfo.setEmail(user.getEmail());
        userInfo.setPhone(user.getPhone());
        userInfo.setRole(user.getRole());
        loginVO.setUserInfo(userInfo);

        return loginVO;
    }

    @Override
    @Transactional
    public String refreshToken(RefreshTokenDTO refreshTokenDTO) {
        // 验证refresh token是否有效
        if (!jwtUtil.validateToken(refreshTokenDTO.getRefreshToken())) {
            throw new RuntimeException("Refresh Token无效或已过期");
        }

        // 检查refresh token类型
        try {
            String tokenType = (String) jwtUtil.getClaimsFromToken(refreshTokenDTO.getRefreshToken()).get("type");
            if (tokenType == null || !"refresh".equals(tokenType)) {
                throw new RuntimeException("Token类型错误");
            }
        } catch (Exception e) {
            throw new RuntimeException("Refresh Token格式错误");
        }

        // 从数据库查找refresh token
        RefreshToken refreshTokenEntity = refreshTokenMapper.findByToken(refreshTokenDTO.getRefreshToken());
        if (refreshTokenEntity == null) {
            throw new RuntimeException("Refresh Token不存在");
        }

        // 检查是否过期
        if (refreshTokenEntity.getExpiresAt().isBefore(LocalDateTime.now())) {
            refreshTokenMapper.deleteById(refreshTokenEntity.getId());
            throw new RuntimeException("Refresh Token已过期");
        }

        // 获取用户信息
        User user = userMapper.selectById(refreshTokenEntity.getUserId());
        if (user == null || !"ACTIVE".equals(user.getStatus())) {
            throw new RuntimeException("用户不存在或已被禁用");
        }

        // 生成新的access token
        return jwtUtil.generateAccessToken(user.getId(), user.getUsername(), user.getRole());
    }

    @Override
    public UserInfoVO getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("用户未登录");
        }

        String username = authentication.getName();
        User user = findByUsername(username);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        UserInfoVO userInfo = new UserInfoVO();
        userInfo.setId(user.getId());
        userInfo.setUsername(user.getUsername());
        userInfo.setEmail(user.getEmail());
        userInfo.setPhone(user.getPhone());
        userInfo.setRole(user.getRole());

        return userInfo;
    }

    @Override
    @Transactional
    public void logout(String refreshToken) {
        if (refreshToken == null || refreshToken.isEmpty()) {
            return;
        }

        // 从数据库删除refresh token
        RefreshToken refreshTokenEntity = refreshTokenMapper.findByToken(refreshToken);
        if (refreshTokenEntity != null) {
            refreshTokenMapper.deleteById(refreshTokenEntity.getId());
        }
    }

    @Override
    public User findByUsername(String username) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        wrapper.eq(User::getDeleted, false);
        return userMapper.selectOne(wrapper);
    }

    @Override
    @Transactional
    public LoginVO register(UserRegisterDTO registerDTO) {
        // 检查用户名是否已存在
        User existingUser = findByUsername(registerDTO.getUsername());
        if (existingUser != null) {
            throw new RuntimeException("用户名已存在");
        }

        // 创建新用户
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        // 加密密码
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setEmail(registerDTO.getEmail());
        user.setPhone(registerDTO.getPhone());
        user.setRole("USER"); // 默认角色为普通用户
        user.setStatus("ACTIVE"); // 默认状态为激活
        user.setCreatedTime(LocalDateTime.now());
        user.setUpdatedTime(LocalDateTime.now());
        user.setDeleted(false);
        user.setVersion(1);

        // 保存用户
        userMapper.insert(user);

        // 生成token
        String accessToken = jwtUtil.generateAccessToken(user.getId(), user.getUsername(), user.getRole());
        String refreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername());

        // 保存refresh token到数据库
        RefreshToken refreshTokenEntity = new RefreshToken();
        refreshTokenEntity.setUserId(user.getId());
        refreshTokenEntity.setToken(refreshToken);
        refreshTokenEntity.setExpiresAt(LocalDateTime.now().plusDays(7));
        refreshTokenEntity.setCreatedTime(LocalDateTime.now());
        refreshTokenMapper.insert(refreshTokenEntity);

        // 构建返回结果
        LoginVO loginVO = new LoginVO();
        loginVO.setAccessToken(accessToken);
        loginVO.setRefreshToken(refreshToken);

        UserInfoVO userInfo = new UserInfoVO();
        userInfo.setId(user.getId());
        userInfo.setUsername(user.getUsername());
        userInfo.setEmail(user.getEmail());
        userInfo.setPhone(user.getPhone());
        userInfo.setRole(user.getRole());
        loginVO.setUserInfo(userInfo);

        log.info("用户 {} 注册成功", registerDTO.getUsername());
        return loginVO;
    }
}

